package algo;

import model.tsp.Problem;
import model.tsp.Solution;

import java.util.List;


public class SimulatedAnnealing extends LocalSearch3 {

    public SimulatedAnnealing(Problem problem) {
        super(problem);
    }

    @Override
    protected Solution improve(Solution solution) {
        double T = 100;
        double Tmin = 0.01;
        double alpha = 0.98;
        double K = 1.0;
        int epochs = 1000;
        int cnt = 1;

        while (T > Tmin) {
            for (int epoch = 0; epoch < epochs; epoch++) {
                Solution newSolution = localSearch(solution);
                int delta = newSolution.getCost() - solution.getCost();
                //如果优于当前解，则直接接受；否则以一定概率接受劣解，为了能跳出局部最优
                if (delta < 0) {
                    solution = newSolution.copy();
                } else {
                    double probability = Math.exp(-delta / (K * T));
                    if (probability > random.nextDouble()) {
                        solution = newSolution.copy();
                        System.out.format("以概率%.2f%%接受劣解, ", 100 * probability);
                    }
                }
                System.out.format("第%d次迭代最优解:%d\n", epoch + cnt * epochs, solution.getCost());
            }

            T = alpha * T;
            cnt++;
        }

        return solution;
    }

    protected Solution localSearch(Solution solution) {
        // 随机选择一个邻域结构进行变换
        int type = random.nextInt(6) + 1;
        List<Integer> newX;
        if (type == 1) {
            newX = neighborhoodOperator1(solution.getPermutation());
        } else if (type == 2) {
            newX = neighborhoodOperator2(solution.getPermutation());
        } else if (type == 3) {
            newX = neighborhoodOperator3(solution.getPermutation());
        } else if (type == 4) {
            newX = neighborhoodOperator4(solution.getPermutation());
        } else if (type == 5) {
            newX = neighborhoodOperator5(solution.getPermutation());
        } else {
            newX = neighborhoodOperator6(solution.getPermutation());
        }
        return new Solution(newX, calculateFitness(newX));
    }


}
